﻿using System.Net.Http.Json;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;

namespace DoNet.Common.Helpers
{
    public class HttpClientHelper : IDisposable
    {
        private readonly HttpClient _httpClient;
        private readonly HttpClientHandler _handler;
        private bool disposed = false;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseAddress">例如"https://api.example.com"</param>
        /// <param name="timeout">超时时间（单位秒）默认100秒</param>
        /// <param name="clientCert">证书</param>
        public HttpClientHelper(string baseAddress = "", int timeout = 100, X509Certificate2? clientCert = null)
        {
            _handler = new HttpClientHandler();
            // 证书配置
            if (clientCert != null)
            {
                _handler.ClientCertificates.Add(clientCert);
                _handler.ServerCertificateCustomValidationCallback = (_, _, _, errors) =>
                {
                    // 标准验证：有效期、颁发者、用途等
                    if (errors != SslPolicyErrors.None) return false;
                    return true;
                };
                //_handler.ServerCertificateCustomValidationCallback = (_, cert, _, _) => cert?.Issuer == "CN=TrustedCA" || cert?.Subject == "CN=TrustedClient";
            }

            _httpClient = new HttpClient(_handler);
            if (!string.IsNullOrEmpty(baseAddress))
                _httpClient.BaseAddress = new Uri(baseAddress);
            _httpClient.Timeout = TimeSpan.FromSeconds(timeout);
        }

        #region 同步方法
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="endpoint">请求地址 "/v1/data"</param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public T? Get<T>(string endpoint, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            using (var response = _httpClient.GetAsync(endpoint).Result)
            {
                response.EnsureSuccessStatusCode();
                return DeserializeResponse<T>(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 "/v1/data"</param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public string GetString<T>(string endpoint, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            using (var response = _httpClient.GetAsync(endpoint).Result)
            {
                response.EnsureSuccessStatusCode();
                return DeserializeResponseString(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 "/v1/data"</param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public byte[] GetBytes<T>(string endpoint, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            using (var response = _httpClient.GetAsync(endpoint).Result)
            {
                response.EnsureSuccessStatusCode();
                return DeserializeResponseBytes(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public Stream GetStream<T>(string endpoint, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            using (var response = _httpClient.GetAsync(endpoint).Result)
            {
                response.EnsureSuccessStatusCode();
                return DeserializeResponseStream(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="data"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public T? Post<T>(string endpoint, object data, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            var content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
            using (var response = _httpClient.PostAsync(endpoint, content).Result)
            {
                response.EnsureSuccessStatusCode();
                return DeserializeResponse<T>(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="data"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public string PostString(string endpoint, object data, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            var content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
            using (var response = _httpClient.PostAsync(endpoint, content).Result)
            {
                response.EnsureSuccessStatusCode();
                return DeserializeResponseString(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="data"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public byte[] PostBytes(string endpoint, object data, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            var content = new StringContent(JsonHelper.SerializeObject(data), Encoding.UTF8, "application/json");
            using (var response = _httpClient.PostAsync(endpoint, content).Result)
            {
                response.EnsureSuccessStatusCode();
                return DeserializeResponseBytes(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="data"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public Stream PostStream(string endpoint, object data, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            var content = new StringContent(JsonHelper.SerializeObject(data), Encoding.UTF8, "application/json");
            using (var response = _httpClient.PostAsync(endpoint, content).Result)
            {
                response.EnsureSuccessStatusCode();
                return DeserializeResponseStream(response);
            }
        }
        private T? DeserializeResponse<T>(HttpResponseMessage response)
        {
            return DeserializeResponseAsync<T>(response).Result;
        }
        private Stream DeserializeResponseStream(HttpResponseMessage response)
        {
            return response.Content.ReadAsStream();
        }
        private string DeserializeResponseString(HttpResponseMessage response)
        {
            return DeserializeResponseStringAsync(response).Result;
        }
        private byte[] DeserializeResponseBytes(HttpResponseMessage response)
        {
            return DeserializeResponseBytesAsync(response).Result;
        }
        #endregion 同步方法

        #region 异步方法
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="endpoint">请求地址 "/v1/data"</param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public async Task<T?> GetAsync<T>(string endpoint, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            using (var response = await _httpClient.GetAsync(endpoint))
            {
                response.EnsureSuccessStatusCode();
                return await DeserializeResponseAsync<T>(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 "/v1/data"</param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public async Task<string> GetStringAsync<T>(string endpoint, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            using (var response = await _httpClient.GetAsync(endpoint))
            {
                response.EnsureSuccessStatusCode();
                return await DeserializeResponseStringAsync(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 "/v1/data"</param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public async Task<byte[]> GetBytesAsync<T>(string endpoint, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            using (var response = await _httpClient.GetAsync(endpoint))
            {
                response.EnsureSuccessStatusCode();
                return await DeserializeResponseBytesAsync(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public async Task<Stream> GetStreamAsync<T>(string endpoint, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            using (var response = await _httpClient.GetAsync(endpoint))
            {
                response.EnsureSuccessStatusCode();
                return await DeserializeResponseStreamAsync(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="data"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public async Task<T?> PostAsync<T>(string endpoint, object data, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            var content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
            using (var response = await _httpClient.PostAsync(endpoint, content))
            {
                response.EnsureSuccessStatusCode();
                return await DeserializeResponseAsync<T>(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="data"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public async Task<string> PostStringAsync(string endpoint, object data, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            var content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
            using (var response = await _httpClient.PostAsync(endpoint, content))
            {
                response.EnsureSuccessStatusCode();
                return await DeserializeResponseStringAsync(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="data"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public async Task<byte[]> PostBytesAsync(string endpoint, object data, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            var content = new StringContent(JsonHelper.SerializeObject(data), Encoding.UTF8, "application/json");
            using (var response = await _httpClient.PostAsync(endpoint, content))
            {
                response.EnsureSuccessStatusCode();
                return await DeserializeResponseBytesAsync(response);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endpoint">请求地址 例如"/v1/data"</param>
        /// <param name="data"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public async Task<Stream> PostStreamAsync(string endpoint, object data, Dictionary<string, string>? headers = null)
        {
            AddHeaders(headers);
            var content = new StringContent(JsonHelper.SerializeObject(data), Encoding.UTF8, "application/json");
            using (var response = await _httpClient.PostAsync(endpoint, content))
            {
                response.EnsureSuccessStatusCode();
                return await DeserializeResponseStreamAsync(response);
            }
        }

        private async Task<T?> DeserializeResponseAsync<T>(HttpResponseMessage response)
        {
            return await response.Content.ReadFromJsonAsync<T>();
        }
        private async Task<Stream> DeserializeResponseStreamAsync(HttpResponseMessage response)
        {
            return await response.Content.ReadAsStreamAsync();
        }
        private async Task<string> DeserializeResponseStringAsync(HttpResponseMessage response)
        {
            return await response.Content.ReadAsStringAsync();
        }
        private async Task<byte[]> DeserializeResponseBytesAsync(HttpResponseMessage response)
        {
            return await response.Content.ReadAsByteArrayAsync();
        }
        #endregion 异步方法


        private void AddHeaders(Dictionary<string, string>? headers)
        {
            if (headers == null) return;
            foreach (var header in headers)
            {
                _httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
            }
        }


        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    _httpClient?.Dispose();
                    _handler?.Dispose();
                }
                disposed = true;
            }
        }

        public void Dispose() {
            Dispose(true); 
        }
    }
}
